// 基于 SnowLang Project (https://gitee.com/jcnc-org/snow) 的衍生作品
// 原始版权归属: Copyright © 2025 Ke Xu (Luke)
// 本实现版权归属: Copyright © 2025 Sany
// 遵循 Apache License 2.0 授权
package module

import (
	"errors"
	"fmt"

	"gitee.com/xntk2381/cc/vm/utils"
)

/**
 * OperandStack class provides the stack management implementation.
 * <p>
 * It uses Deque (ArrayDeque) to implement basic stack operations, including push, pop, checking if the stack is empty,
 * getting the stack size, and printing the stack's current state.
 * </p>
 */
type OperandStack struct {
	stack []interface{}
}

/**
 * Default constructor for creating an instance of OperandStack.
 * This constructor is empty as no specific initialization is required.
 */
func NewOperandStack() *OperandStack {
	return &OperandStack{
		stack: make([]interface{}, 0),
	}
}

/**
 * Push operation, adds an integer value to the stack.
 * <p>
 * The push operation is implemented using Deque's push method to add the integer value to the top of the stack.
 * </p>
 *
 * @param value The value to be pushed onto the stack.
 */
func (s *OperandStack) Push(value interface{}) {
	s.stack = append(s.stack, value)
}

/**
 * Pop operation, removes and returns the top element of the stack.
 * <p>
 * The pop operation is implemented using Deque's pop method. If the stack is empty, an exception will be thrown.
 * </p>
 *
 * @return The top element of the stack.
 * @throws IllegalStateException If the stack is empty, an exception is thrown indicating that the pop operation cannot be performed.
 */
func (s *OperandStack) Pop() (interface{}, error) {
	if s.IsEmpty() {
		return nil, errors.New("stack is empty, cannot pop")
	}
	val := s.stack[len(s.stack)-1]
	s.stack = s.stack[:len(s.stack)-1]
	return val, nil
}

/**
 * Checks if the stack is empty.
 * <p>
 * The isEmpty method of Deque is used to check if the stack is empty.
 * </p>
 *
 * @return Returns true if the stack is empty, otherwise false.
 */
func (s *OperandStack) IsEmpty() bool {
	return len(s.stack) == 0
}

/**
 * Gets the current size of the stack.
 * <p>
 * The size method of Deque is used to get the size of the stack, which is the number of elements in the stack.
 * </p>
 *
 * @return The number of elements in the stack.
 */
func (s *OperandStack) Size() int {
	return len(s.stack)
}

/**
 * Prints the current state of the stack.
 * <p>
 * Logs the list of all elements in the stack, showing its content. Uses LoggingUtils to log the information.
 * </p>
 */
func (s *OperandStack) PrintOperandStack() {
	utils.LogInfo("Operand Stack state:", fmt.Sprintf("%v", s.stack))
}

/**
 * Retrieves the top value of the stack without removing it.
 * <p>This method returns the top element of the stack without modifying the stack itself.</p>
 *
 * @return The top value of the stack.
 * @throws EmptyStackException if the stack is empty.
 */
func (s *OperandStack) Peek() (interface{}, error) {
	if s.IsEmpty() {
		return nil, errors.New("stack is empty")
	}
	return s.stack[len(s.stack)-1], nil
}
